package com.example.demokotlin

import org.junit.Test


/**
 * 函数式编程测试
 * 过滤filter: 过滤函数接收一个predicate函数，
 * 用它给定的条件检查接受者集合李的元素并给出true或者false判定。
 * 如果返回true，受检元素则会添加到过滤返回的新集合中。
 * 如果返回false，那么受检元素就会移出新集合
 *
 * @author zhouronghua
 * @time 2021/9/20 2:22 下午
 */
class FilterTest {

    /**
     * 过滤集合中以字母J开头的单词
     *
     * @author zhouronghua
     * @time 2021/9/20 2:26 下午
     */
    @Test
    fun testFilterWords() {
        println("=== filter根据条件过滤元素 ===")
        val list = listOf("Kate", "Jimmy", "Jacky", "Lucy")
        val result = list.filter {
            it.startsWith("J")
        }
        println(result)
        // 测试嵌套集合的过滤
        val items = listOf(
            listOf("red apple", "green apple", "blue apple"),
            listOf("red fish", "golden fish"),
            listOf("yellow banana", "teal banana")
        )
        // 1) 过滤二级列表中包含red的元素
        // 2) 将得到的列表进行打平
        val filterItems = items.flatMap { it ->
            it.filter {
                it.contains("red")
            }
        }
        println(filterItems)
        // Map的过滤
        val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
        val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10 }
        println(filteredMap)
    }

    /**
     * 过滤集合中类的实例
     *
     * @author zhouronghua
     * @time 2021/9/20 2:40 下午
     */
    @Test
    fun testFilterIsInstance() {
        println("=== filterIsInstance过滤集合中指定类的实例 ===")
        val items = listOf(null, "this is China", "Like Lucy", 100, "Four")
        val filterItems = items.filterIsInstance<String>()
        println(filterItems)
        // 将字符串元素项变为大写输出
        filterItems.forEach {
            println(it.toUpperCase())
        }
        // 过滤列表List<T: Any>中的非空项
        val notEmptyItems = items.filterNotNull()
        println(notEmptyItems)
    }

    /**
     * 测试划分
     * 过滤函数 – partition() – 通过一个谓词过滤集合并且将不匹配的元素存放在一个单独的列表中。
     *
     * @author zhouronghua
     * @time 2021/9/20 3:22 下午
     */
    @Test
    fun testPartition() {
        val numbers = listOf("one", "two", "three", "four")
        val (match, rest) = numbers.partition { it.length > 3 }
        // 满足过滤条件的列表
        println(match)
        // 不满足过滤条件的列表
        println(rest)
    }

    /**
     * 检查谓词
     * 如果至少有一个元素匹配给定谓词，那么 any() 返回 true
     * 如果没有元素与给定谓词匹配，那么 none() 返回 true
     * 如果所有元素都匹配给定谓词，那么 all() 返回 true。注意，
     * 在一个空集合上使用任何有效的谓词去调用 all() 都会返回 true 。
     * 这种行为在逻辑上被称为 vacuous truth。
     * any() 和 none() 也可以不带谓词使用：在这种情况下它们只是用来检查集合是否为空。
     * 如果集合中有元素，any() 返回 true，否则返回 false；none() 则相反。
     *
     * @author zhouronghua
     * @time 2021/9/20 3:26 下午
     */
    @Test
    fun testCheckPredicate() {
        println("=== any/none/all谓词检测 ===")
        val numbers = listOf("one", "two", "three", "four")
        // 至少一个满足匹配条件
        println(numbers.any { it.endsWith("e") })
        // 没有满足条件的项，返回true
        println(numbers.none { it.endsWith("a") })
        println(numbers.all { it.endsWith("e") })

        println(emptyList<Int>().all { it > 5 })
        // 只判断是否为空
        val empty = emptyList<String>()
        println(numbers.any())
        println(empty.any())
        println(numbers.none())
        println(empty.none())
    }

    /**
     * 通过filter和map查找素数
     *
     * @author zhouronghua
     * @time 2021/9/20 3:55 下午
     */
    @Test
    fun testFilterMap() {
        val numbers = listOf(4, 7, 8, 11, 28, 118)
        val primes = numbers.filter { number ->
            // 只能被1和自身整除的函数，2~number-1都不能整除
            (2 until number).map {
                number % it
            }.none {
                it == 0
            }
        }
        print(primes)
    }
}